﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
//
using PerceptiveMCAPI.Types;
//
namespace PerceptiveMCAPI
{
	internal static class Validator
	{
		// --------------------- message formatter
		internal static Api_ValidatorMessage FormatMsg( EnumValues.MessageLevel msg_level, string msg_property, string msg_text )
		{
			Api_ValidatorMessage val = new Api_ValidatorMessage
			{
				MessageLevel = msg_level,
				PropertyName = msg_property,
				MessageText = msg_text
			};
			return val;
		}

		#region ------------------------------------------------------------------------- Multi-Use

		// apikey 
		internal static Api_ValidatorMessage apikey_valid( string apikey )
		{
			// TODO: ?? validate format of apikey
			if ( string.IsNullOrEmpty( apikey ) )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "apikey", "apikey was not specified, or has an invalid format." );
			}
			return null;
		}
		// cid
		internal static Api_ValidatorMessage cid_valid( string cid )
		{
			// TODO: ?? validate format of cid
			if ( string.IsNullOrEmpty( cid ) )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "cid", "Campaign Id, 'cid', was not specified, or has an invalid format." );
			}
			return null;
		}
		// id (listId)
		internal static Api_ValidatorMessage ListId_valid( string id )
		{
			// TODO: ?? validate format of id
			if ( string.IsNullOrEmpty( id ) )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "id", "List Id, 'id', was not specified, or has an invalid format." );
			}
			return null;
		}
		// email
		internal static Api_ValidatorMessage email_valid( string email )
		{
			if ( string.IsNullOrEmpty( email ) )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "email", "An email address is required and was not provided." );
			}
			//
			if ( !EnumValues.rexEmail.IsMatch( email ) )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "email", string.Format( "The email address: [{0}] is not properly formed.", email ) );
			}
			//
			return null;
		}
		// email_type_valid
		internal static Api_ValidatorMessage email_type_valid( EnumValues.emailType emailType )
		{
			if ( emailType == EnumValues.emailType.NotSpecified )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "email_type", "The 'email_type' was not specified." );
			}
			return null;
		}
		// folder_type_valid
		internal static Api_ValidatorMessage folder_type_valid( EnumValues.folder_type folder_type )
		{
			if ( folder_type == EnumValues.folder_type.NotSpecified )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "folder_type", "The 'folder_type' was not specified." );
			}
			return null;
		}
		// template_type_valid
		internal static Api_ValidatorMessage template_type_valid( EnumValues.template_type template_type )
		{
			if ( template_type == EnumValues.template_type.NotSpecified )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "template_type", "The 'template_type' was not specified." );
			}
			return null;
		}
		// url_valid
		internal static Api_ValidatorMessage url_valid( string url )
		{
			if ( string.IsNullOrEmpty( url ) )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "url", "'url' is required and was not provided." );
			}

			try
			{
				// if url doesn't contain :// specified, prefix it before the test so the uri works
				// webhooks allows a url w/o the protocol 
				string t_Url = url.Trim();
				if ( !t_Url.Contains( "://" ) ) t_Url = string.Concat( "http://", t_Url );

				Uri address = new Uri( t_Url );
				if ( address.Scheme != Uri.UriSchemeHttp && address.Scheme != Uri.UriSchemeHttps )
					return FormatMsg( EnumValues.MessageLevel.Error, "url",
						string.Format( "The url: '{0}' is not properly formed.", url ) );
				if ( address.HostNameType != UriHostNameType.Dns )
					return FormatMsg( EnumValues.MessageLevel.Error, "url",
						string.Format( "The url: '{0}' is not properly formed.", url ) );
				//
				if ( !EnumValues.rexUrl.IsMatch( t_Url ) )
				{
					return FormatMsg( EnumValues.MessageLevel.Error, "url",
						string.Format( "The url: '{0}' is not properly formed.", url ) );
				}
				//            
				return null;
			}
			catch ( Exception ex )
			{
				if ( ex.InnerException != null ) ex = ex.InnerException;
				return FormatMsg( EnumValues.MessageLevel.Error, "url",
					string.Format( "The url: '{0}' is not properly formed. {1}", url, ex.Message ) );
			}
		}
		// url_working
		internal static Api_ValidatorMessage url_working( string url )
		{
			// check valid before trying to find it
			Api_ValidatorMessage url_valid_msg = url_valid( url );
			if ( url_valid_msg != null ) return url_valid_msg;

			// if url doesn't contain :// prefix it before the test so the url works
			// webhooks allows a url w/o the protocol 
			string t_Url = url.Trim();
			if ( !t_Url.Contains( "://" ) ) t_Url = string.Concat( "http://", t_Url );
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create( t_Url );
			HttpWebResponse response = null;
			int code = 0;

			try
			{
				response = (HttpWebResponse)request.GetResponse();
				int.TryParse( response.StatusCode.ToString(), out code );
				if ( code > 299 ) throw new ApplicationException( string.Format( "Http response code: {0}", code ) );
			}
			catch ( Exception ex )
			{
				if ( ex.InnerException != null ) ex = ex.InnerException;
				return FormatMsg( EnumValues.MessageLevel.Error, "url",
					string.Format( "The call to url: '{0}' returned in error. {1}", url, ex.Message ) );
			}
			//            
			return null;
		}
		// since
		internal static Api_ValidatorMessage since_valid( DateTime since )
		{
			if ( since > DateTime.UtcNow )
			{
				return FormatMsg( EnumValues.MessageLevel.Warning, "since", "'since' date/time cannot be in the future. All times are UTC." );
			}
			return null;
		}
		// start
		internal static Api_ValidatorMessage start_valid( int start )
		{
			if ( start < 0 )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "start",
					"'start' must be an integer greater than or equal to 0" );
			}
			return null;
		}
		// limit
		internal static Api_ValidatorMessage limit_valid( int limit, int maxLimit )
		{
			if ( limit < 1 || limit > maxLimit )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, "limit",
				 string.Format( "'limit' must be greater than 0 and less than the maximum of {0:N0}.", maxLimit ) );
			}
			return null;
		}
		// merge_vars
		internal static Api_ValidatorMessage merge_vars_valid( Dictionary<string, object> merge_vars )
		{
			// Merge_vars aren't required for sub, upd -- so existence error isn't an issue
			// blank values are valid -- they clear out values, so what to edit?
			// warning if none entered?
			// can only validate required if I grab the existing MVs and do a check, 
			//       which is not a plain wrapper -- it's more admin
			//
			// Hmmm... need to ponder.

			if ( merge_vars.Count == 0 )
			{
				return FormatMsg( EnumValues.MessageLevel.Warning, "merge_vars", "No 'merge_vars' were provided." );
			}
			return null;
		}
		// Not implemented 
		internal static Api_ValidatorMessage api_NotImplemented( string api_Method )
		{
			return FormatMsg( EnumValues.MessageLevel.Terminal, EnumValues.valNoProperty,
				string.Format( "Method '{0}' is not currently implemented", api_Method ) );
		}
		// Deprecated
		internal static Api_ValidatorMessage deprecated( string api_Method )
		{
			return FormatMsg( EnumValues.MessageLevel.Warning, EnumValues.valNoProperty,
			 string.Format( "Method '{0}' has been deprecated. It is suggested that an alternate method is used.", api_Method ) );
		}

		#endregion

		#region --------------------------------- Generic existence, type checks

		// check for empty string
		internal static Api_ValidatorMessage string_value_required( string value, string parmName )
		{
			if ( string.IsNullOrEmpty( value ) )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, parmName,
					string.Format( "Required parameter '{0}' was not specified.", parmName ) );
			}
			return null;
		}
		// check for positive integer
		internal static Api_ValidatorMessage int_value_required( int value, string parmName )
		{
			if ( value < 1 )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, parmName,
					string.Format( "Integer value '{0}' must be greater than 0.", parmName ) );
			}
			return null;
		}
		// check of type
		internal static Api_ValidatorMessage parameter_type_valid( string name, string type, object parm )
		{
			string parm_type = parm.GetType().Name;
			if ( parm_type.ToLower() != type.ToLower() )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, name,
					string.Format( "Parameter '{0}' type is {1}. Type of {2} was expected.", name, parm_type, type ) );
			}
			return null;
		}

		// check collection has entries
		internal static Api_ValidatorMessage collection_has_entries( ICollection value, string parmName )
		{
			if ( value == null && value.Count == 0 )
			{
				return FormatMsg( EnumValues.MessageLevel.Error, parmName,
					string.Format( "Collection '{0}' is null or empty.", parmName ) );
			}
			return null;
		}


		#endregion

	}
}
